perm filename RAW.C[IP,SYS] blob
sn#680189 filedate 1982-10-07 generic text, type T, neo UTF8
#include "../h/param.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../bbnnet/mbuf.h"
#include "../bbnnet/net.h"
#include "../bbnnet/ifcb.h"
#include "../bbnnet/ip.h"
#include "../bbnnet/tcp.h"
#include "../bbnnet/icmp.h"
#include "../bbnnet/raw.h"
#include "../bbnnet/udp.h"
#include "../bbnnet/ucb.h"
extern struct user u;
/*
* Put raw message input on user receive queue. Called from ip_input or local
* net input routine. Dispatches on link/protocol number and source and
* destination address.
*/
raw_input(mp, src, dst, link, mask, error)
register struct mbuf *mp;
struct socket *src;
struct socket *dst;
short link;
int mask, error;
{
register struct proto *p;
register struct mbuf *m;
register struct ucb *up;
int copied, queued;
copied = TRUE;
queued = FALSE;
/* get proto dispatch queue header */
p = (struct proto *)&protab[PRHASH(link)];
while ((p = p->pr_next) != NULL) {
m = dtom(p);
up = (struct ucb *)m->m_act;
/* dispatch on link number, and src/dst address */
if (p->pr_num == link && up != NULL &&
(up->uc_flags & mask) &&
(up->uc_host.s_addr == NULL ||
src->s_addr == up->uc_host.s_addr) &&
(up->uc_local.s_addr == NULL ||
dst->s_addr == up->uc_local.s_addr) &&
(!error || (error && up->uc_flags&RAWERR))) {
/* if conns for this proto remain, copy the message,
otherwise just put it on ucb read queue */
copied = FALSE;
if (p->pr_next != NULL)
if ((m = m_copy(mp)) != NULL)
copied = TRUE;
/* if last copy was successful, enqueue the
message, otherwise tell user something
was dropped */
if (mp != NULL)
queued = raw_queue(mp, up);
else
to_user(up, UDROP);
mp = m;
}
}
if (copied) /* drop anything left over */
m_freem(mp);
if (queued)
netstat.net_drops++;
}
/*
* Dispatch message to other IP/TCP/ICMP/GGP modules. For each requestor,
* copy raw message and place it on user input queue.
*/
raw_disp(m, p)
register struct mbuf *m;
register struct proto *p;
{
register struct mbuf *n, *mm;
register struct ucb *up;
while (p != NULL) {
mm = dtom(p);
if ((up = (struct ucb *)mm->m_act) == NULL)
return;
p = p->pr_next;
/* no mbufs for copy, just tell user;
otherwise copy and dispatch */
if (m == NULL)
to_user(up, UDROP);
else {
if (p != NULL)
n = m_copy(m);
raw_queue(m, up);
m = n;
}
}
}
/*
* Put raw message chain on specified ucb's read queue. Make sure buffer
* limit is not exceeded. Message will either all fit, or be dropped.
*/
raw_queue(mp, up)
register struct mbuf *mp;
register struct ucb *up;
{
register count;
register struct mbuf *m;
/* drop if no buffer space availble for conn */
/* have buffer space, chain to user rcv buf */
for (m = mp, count = 0; m != NULL; m = m->m_next)
count++;
if (count + up->uc_rsize <= up->uc_rcv) {
mp->m_act = NULL;
while (up->uc_flags & ULOCK)
sleep(&up->uc_flags, PZERO);
up->uc_flags |= ULOCK;
up->uc_rsize += count;
if ((m = up->uc_rbuf) == NULL)
up->uc_rbuf = mp;
else {
while (m->m_act != NULL)
m = m->m_act;
m->m_act = mp;
}
up->uc_flags &= ~ULOCK;
wakeup(&up->uc_flags);
/* wake up raw read */
wakeup(up);
return(TRUE);
} else {
to_user(up, UDROP);
m_freem(mp);
return(FALSE);
}
}
/*
* Add protocol entry to ucb proto block, adding new blocks as needed. Insert
* proto entry to global proto header chain.
*/
raw_add(up, prnum)
register struct ucb *up;
short prnum;
{
register struct mbuf *m, *n;
register struct proto *p, *q;
register i;
/* first, make sure we don't already have this prnum */
p = profind(up, prnum);
while ((p = p->pr_next) != NULL) {
m = dtom(p);
if (p->pr_num == prnum && up == (struct ucb *)m->m_act)
return;
}
p = up->uc_proto;
n = m = dtom(p);
getnew:
/* find first non-full proto block on ucb list */
while (m != NULL && m->m_len == NPRMB) {
n = m;
m = m->m_next;
}
/* no proto block or all full */
if (p == NULL || m == NULL) {
/* get new proto block */
if ((m = m_get(1)) == NULL) {
u.u_error = ENETBUF;
return;
}
m->m_next = NULL;
m->m_act = (struct mbuf *)up;
m->m_len = 0;
/* mark free all entries in proto block */
p = (struct proto *)((int)m + MHEAD);
for (q=p,i=NPRMB; i > 0; i--,q++) {
q->pr_next = NULL;
q->pr_flag = 0;
}
/* chain new proto block to ucb */
if (n == NULL)
up->uc_proto = p;
else
n->m_next = m;
}
/* look for first free entry in proto block */
for (i=NPRMB; i > 0; i--, p++) {
if (p->pr_flag == 0) {
p->pr_num = prnum;
p->pr_flag |= PRUSED;
m->m_len++;
/* find proto header, and add entry to chain */
q = profind(up, prnum);
while (q->pr_next != NULL)
q = q->pr_next;
q->pr_next = p;
return;
}
}
/* just in case # of free proto entries lies, make full and retry */
m->m_len = NPRMB;
goto getnew;
}
/*
* Free all proto entries and blocks on this ucb.
*/
raw_free(up)
register struct ucb *up;
{
register i;
register struct proto *p;
register struct mbuf *m;
if ((p = up->uc_proto) == NULL)
return;
up->uc_proto = NULL;
m = dtom(p);
while (m != NULL) {
for (i=NPRMB; i > 0; i--,p++)
if (p->pr_flag & PRUSED)
prodel(up, p);
m = m_free(m);
}
}
/*
* Find specified proto entry and delete from ucb proto block.
*/
raw_del(up, prnum)
register struct ucb *up;
register short prnum;
{
register struct proto *p;
register struct mbuf *m;
p = profind(up, prnum);
while ((p = p->pr_next) != NULL)
if (p->pr_num == prnum) {
m = dtom(p);
if (up == (struct ucb *)m->m_act) {
prodel(up, p);
return;
}
}
u.u_error = ENETRNG;
}
/*
* Fill array with protocol numbers from ucb proto block
*/
raw_stat(up, protp, protlen)
struct ucb *up;
register short *protp;
register protlen;
{
register i;
register struct proto *p;
register struct mbuf *m;
p = up->uc_proto;
m = dtom(p);
while (m != NULL) {
for (i = NPRMB; i > 0; i--,p++) {
if (p->pr_flag & PRUSED) {
if (protlen > 0) {
if (copyout((caddr_t)&p->pr_num,
(caddr_t)protp,
sizeof(short))) {
u.u_error = EFAULT;
return;
}
protlen -= sizeof(short);
protp++;
} else
return;
}
}
m = m->m_next;
p = (struct proto *)((int)m + MHEAD);
}
}
/*
* Delete proto entry from ucb proto block and corresponding global proto chain
*/
prodel(up, p)
struct ucb *up;
register struct proto *p;
{
register struct proto *q, *r;
register short prnum;
register struct mbuf *m;
if (p == NULL)
return;
prnum = p->pr_num;
r = profind(up, prnum);
q = r->pr_next;
while (q != NULL) {
if (q->pr_num == prnum && q == p) {
r->pr_next = p->pr_next;
break;
}
r = q;
q = q->pr_next;
}
p->pr_next = NULL;
p->pr_flag = 0;
m = dtom(p);
if (m->m_len != 0)
m->m_len--;
}
/*
* Find correct proto chain header.
*/
struct proto *profind(up, prnum)
register struct ucb *up;
register short prnum;
{
register struct proto *p;
/* check "built-in" proto headers first, then proto hash table
for header */
if (prnum == TCPROTO && up->uc_flags&UIP)
p = (struct proto *)&netcb.n_tcp_proto;
else if (prnum == up->uc_srcif->if_link && up->uc_flags&URAW)
p = (struct proto *)&netcb.n_ip_proto;
else if (prnum == ICMPROTO && up->uc_flags&UIP)
p = (struct proto *)&netcb.n_icmp_proto;
else if (prnum == GGPROTO && up->uc_flags&UIP)
p = (struct proto *)&netcb.n_ggp_proto;
else if (prnum == UDPROTO && up->uc_flags&UIP)
p = (struct proto *)&netcb.n_udp_proto;
else
p = (struct proto *)&protab[PRHASH(prnum)];
return(p);
}